import os
import json
import re
from typing import Any, Dict


class Config:
    def __init__(self, config_path: str=None):
        if config_path is None:
            config_path = 'config/config.json'
        self.config = self._load_config(config_path)

    def _load_config(self, config_path: str) -> Dict[str, Any]:
        """Load configuration from JSON file and process environment variables."""
        if not os.path.exists(config_path):
            raise FileNotFoundError(f"Configuration file not found: {config_path}")

        with open(config_path, 'r') as f:
            config = json.load(f)

        return self._process_env_vars(config)

    def _process_env_vars(self, config: Dict[str, Any]) -> Dict[str, Any]:
        """Recursively process environment variables in configuration."""
        if isinstance(config, dict):
            return {k: self._process_env_vars(v) for k, v in config.items()}
        elif isinstance(config, list):
            return [self._process_env_vars(v) for v in config]
        elif isinstance(config, str):
            pattern = r'\${([^}]+)}'
            match = re.search(pattern, config)
            if match:
                env_var = match.group(1)
                env_value = os.getenv(env_var)
                if env_value is None:
                    raise ValueError(f"Environment variable not found: {env_var}")
                return config.replace(f"${{{env_var}}}", env_value)
        return config

    def get(self, key: str, default: Any = None) -> Any:
        """Get configuration value by key."""
        keys = key.split('.')
        value = self.config
        try:
            for k in keys:
                value = value[k]
            return value
        except (KeyError, TypeError):
            return default

    @property
    def openai_config(self) -> Dict[str, Any]:
        """Get OpenAI configuration."""
        return self.get('openai', {})

    @property
    def app_config(self) -> Dict[str, Any]:
        """Get application configuration."""
        return self.get('app', {})

    @classmethod
    def get_instance(cls, config_path: str=None) -> 'Config':
        """Get singleton instance of Config."""
        if not hasattr(cls, '_instance'):
            cls._instance = cls(config_path)
        return cls._instance


def get_config(config_path: str=None) -> Config:
    return Config.get_instance(config_path)


